package tcp_proxy_router

import (
	"context"
	"go_gateway/tcp_server"
	"math"
	"net"
)

const abortIndex int8 = math.MaxInt8 / 2

type TcpHandlerFunc func(*TcpRouterContext)

type TcpRouterContext struct {
	*TcpGroup
	conn  net.Conn
	Ctx   context.Context
	index int8
}

func newTcpRouterContext(conn net.Conn, r *TcpRouter, ctx context.Context) *TcpRouterContext {

	c := &TcpRouterContext{
		conn:     conn,
		TcpGroup: r.TcpGroup,
		Ctx:      ctx,
	}
	c.Reset()
	return c
}

func (c *TcpRouterContext) Get(key interface{}) interface{} {
	return c.Ctx.Value(key)
}

func (c *TcpRouterContext) Set(key, val interface{}) {
	c.Ctx = context.WithValue(c.Ctx, key, val)
}

type TcpRouterHandler struct {
	coreFunc func(*TcpRouterContext) tcp_server.TCPHandler
	router   *TcpRouter
}

func (h *TcpRouterHandler) ServeTCP(ctx context.Context, conn net.Conn) {
	c := newTcpRouterContext(conn, h.router, ctx)
	c.handlers = append(c.handlers, func(c *TcpRouterContext) {
		h.coreFunc(c).ServeTCP(ctx, conn)
	})
	c.Reset()
	c.Next()
}

func NewTcpRouterHandler(coreFunc func(*TcpRouterContext) tcp_server.TCPHandler, router *TcpRouter) *TcpRouterHandler {
	return &TcpRouterHandler{
		coreFunc: coreFunc,
		router:   router,
	}
}

type TcpRouter struct {
	*TcpGroup
}

func NewTcpRouter() *TcpRouter {
	return &TcpRouter{
		TcpGroup: &TcpGroup{
			path: "/",
		},
	}
}

type TcpGroup struct {
	*TcpRouter
	path     string
	handlers []TcpHandlerFunc
}

func (g *TcpGroup) Group(path string) *TcpGroup {
	if path != "/" {
		panic("only accept path=/")
	}
	return g.TcpGroup
}

func (g *TcpGroup) Use(middleware ...TcpHandlerFunc) *TcpGroup {
	g.handlers = append(g.handlers, middleware...)
	return g
}

func (c *TcpRouterContext) Next() {
	c.index++
	for c.index < int8(len(c.handlers)) {
		c.handlers[c.index](c)
		c.index++
	}
}

func (c *TcpRouterContext) Abort() {
	c.index = abortIndex
}

func (c *TcpRouterContext) IsAborted() bool {
	return c.index >= abortIndex
}

func (c *TcpRouterContext) Reset() {
	c.index = -1
}
